/************************************************************************
 *   IRC - Internet Relay Chat, src/m_chgcmds.c
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 1, or (at your option)
 *   any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "struct.h"
#include "common.h"
#include "sys.h"
#include "numeric.h"
#include "channel.h"
#include "msg.h"		  /* For TOK_*** and MSG_*** strings  */
#include "hash.h"		  /* For CHANNELHASHSIZE */
#include "h.h"

/*
   **
   ** This file holds the CHG* and SET* commands
   ** Oper+ Commands: SETNAME
   ** Server Admin+ Commands: SETIDENT
   ** Services Oper+ Commands: SETHOST, CHGNAME, CHGIDENT
   ** Services Root Only: CHGHOST
   **
 */

//Macro borrowed from Unreal
#define GetHost(x)			(IsHidden(x) ? (x)->user->mask : (x)->user->host)

/*
 * m_setname() added by Kei
 * 2007-Mar-21
 * parv[0] - sender
 * parv[1] - new realname
 */
int m_setname(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
 	if ((parc < 2) || BadPtr(parv[1]))
 	{
 		sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "SETNAME");
 		return 0;
	}

	if (strlen(parv[1]) > REALLEN)
	{
		if (MyConnect(sptr))
		{
			sendto_one(sptr, ":%s 514 %s :*** /SetName Error: \"Real names\" may maximum be %i characters of length",
				me.name, sptr->name, REALLEN);
		}
		return 0;
	}

	/* set the new name before we check, but don't send to servers unless it is ok */
	strcpy(sptr->info, parv[1]);

	sendto_serv_butone(cptr, ":%s SETNAME :%s", sptr->name, parv[1]);

	if (MyConnect(sptr))
		sendto_one(sptr, ":%s 514 %s :*** Your \"real name\" is now set to be %s",
				me.name, sptr->name, parv[1]);

	return 0;
}

/*
 * m_chgname() added by Kei
 * 2005-Aug-13
 * parv[0] - sender
 * parv[1] - nick whose realname we are changing
 * parv[2] - new realname
 */
int m_chgname(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
	aClient *acptr;

	if (parc < 2) {
		sendto_one (sptr, err_str (ERR_NONICKNAMEGIVEN), me.name, parv[0]);
		return 0;
    }
	else if (parc < 3) {
		sendto_one (sptr, err_str (ERR_NEEDMOREPARAMS), me.name, parv[0],
		    "CHGNAME");
		return 0;
	}
	else if (MyClient(sptr) && !IsAnOper(sptr)) {
		sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name,
		    parv[0]);
		return 0;
	}
	else {
		if ((acptr = find_person(parv[1], NULL))) {
			strcpy(acptr->info, parv[2]);
			//sendto_serv_butone(cptr, ":%s CHGNAME %s :%s", sptr, parv[1], parv[2]);
			if (IsPerson (sptr) || IsServer (cptr)) {
				if (hunt_server (cptr, sptr, ":%s CHGNAME %s :%s", 1, parc, parv) != HUNTED_ISME) {
					sendto_realops("%s used CHGNAME for %s [%s]", parv[0], parv[1], parv[2]);
					return 0;
				}
			}
			sendto_realops("%s used CHGNAME for %s [%s]", parv[0], parv[1], parv[2]);
			return 1;
		}
		else {
			sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, sptr->name, parv[1]);
			return 0;
		}
	}
}

/*
 * m_setident() added by Kei
 * 2007-Mar-21
 * parv[0] - sender
 * parv[1] - new ident
 */

int m_setident(aClient *cptr, aClient *sptr, int parc, char *parv[])
{

	char *vident, *s;

	int  legalident = 1;	/* is legal characters? */

	if (!IsAnOper(sptr) && MyConnect(sptr))
	{
		sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name,
			parv[0]);
		return 0;
	}

	if (parc < 2)
		vident = NULL;
	else
		vident = parv[1];

	/* bad bad bad boys .. ;p */
	if (vident == NULL)
	{
		if (MyConnect(sptr))
		{
			sendto_one(sptr,
			    ":%s 514 %s :*** SETIDENT Error - Syntax: /SetIdent <new ident>",
			    me.name, parv[0]);
		}
		return 1;
	}
	if (strlen(parv[1]) < 1)
	{
		if (MyConnect(sptr))
			sendto_one(sptr,
			    ":%s 514 %s :*** SETIDENT Error: Must give a parameter (including the ':' symbol)!",
			    me.name, sptr->name);
		return 0;
	}

	/* too large huh? */
	if (strlen(vident) > (USERLEN))
	{
		if (MyConnect(sptr))
			sendto_one(sptr,
			    ":%s 514 %s :*** SETIDENT Error: Usernames are limited to %i characters.",
			    me.name, sptr->name, USERLEN);
		return 0;
	}

	/* illegal?! */
	for (s = vident; *s; s++)
	{
		if ((*s == '~') && (s == vident))
			continue;
		if (!isallowed(*s))
		{
			legalident = 0;
			break;
		}
	}

	if (legalident == 0)
	{
		sendto_one(sptr,
		    ":%s 514 %s :*** SETIDENT Error: A username may only contain a-z, A-Z, 0-9, '-', '~', '.'",
		    me.name, parv[0]);
		return 0;
	}

	/* get it in */
	sprintf(sptr->user->username, "%s", vident);
	/* spread it out */
	sendto_serv_butone(cptr, ":%s SETIDENT :%s", parv[0], parv[1]);

	if (MyConnect(sptr))
	{
		sendto_one(sptr,
		    ":%s 514 %s :*** SETIDENT: Your mask is now (%s!%s@%s)",
		    me.name, parv[0], parv[0], sptr->user->username, GetHost(sptr));
	}
	return 0;
}

/*
 * m_chgident() added by Kei
 * 2007-Mar-21
 * parv[0] - sender
 * parv[1] - nick to change
 * parv[2] - new ident
 */

int m_chgident(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
	aClient *acptr;
	char *s;
	int  legalident = 1;

	if (MyClient(sptr) && !IsSAdmin(sptr))
	{
		sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
		return 0;
	}

	if ((parc < 3) || !*parv[2])
	{
		sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, sptr->name, "CHGIDENT");
		return 0;
	}

	if (strlen(parv[2]) > (USERLEN))
	{
		sendto_one(sptr, ":%s 514 %s :*** CHGIDENT Error: Rejected ident - exceed max length",
			me.name, sptr->name);
		return 0;
	}

	/* illegal?! */
	for (s = parv[2]; *s; s++)
	{
		if ((*s == '~') && (s == parv[2]))
			continue;
		if (!isallowed(*s))
		{
			legalident = 0;
		}
	}

	if (legalident == 0)
	{
		sendto_one(sptr, ":%s 514 %s :*** CHGIDENT Error: A ident may only contain a-z, A-Z, 0-9, '-' & '.'",
			me.name, sptr->name);
		return 0;
	}

	if ((acptr = find_person(parv[1], NULL)))
	{
		if (!IsULine(sptr, sptr))
		{
			sendto_umode(UMODE_OPER,
			    "%s changed the ident of %s (%s@%s) to be %s",
			    sptr->name, acptr->name, acptr->user->username,
			    GetHost(acptr), parv[2]);
		}



		sendto_serv_butone(cptr, ":%s CHGIDENT %s :%s",
			sptr->name, acptr->name, parv[2]);

		sprintf(acptr->user->username, "%s", parv[2]);

		return 0;
	}
	else
	{
		sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, sptr->name,
		    parv[1]);
		return 0;
	}
	return 0;
}

/*
 * m_sethost() added by Kei
 * 2007-Mar-21
 * parv[0] - sender
 * parv[1] - new host
*/
int m_sethost(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
	char *vhost;

	if (!IsSAdmin(sptr))
	{
		sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name,
			parv[0]);
		return 0;
	}

	if (parc < 2)
		vhost = NULL;
	else
		vhost = parv[1];

	/* bad bad bad boys .. ;p */
	if (vhost == NULL)
	{
		if (MyConnect(sptr))
		{
			sendto_one(sptr,
			    ":%s 514 %s :*** SETHOST Error - Syntax: /SetHost <new host>",
			    me.name, parv[0]);
		}
		return 0;
	}

	if (strlen(parv[1]) < 1)
	{
		if (MyConnect(sptr))
			sendto_one(sptr,
			    ":%s 514 %s :*** SETHOST Error: Must specify host (/SetHost <NewHost>)",
			    me.name, sptr->name);
		return 0;
	}
	/* too large huh? */
	if (strlen(parv[1]) > (HOSTLEN))
	{
		if (MyConnect(sptr))
			sendto_one(sptr,
			    ":%s 514 %s :*** SETHOST Error: Hostnames are limited to %i characters.",
			    me.name, sptr->name, HOSTLEN);
		return 0;
	}

	if (!valid_host(vhost))
	{
		sendto_one(sptr,
		    ":%s NOTICE %s :*** SETHOST Error: A hostname may only contain a-z, A-Z, 0-9, '-', '.'",
		    me.name, parv[0]);
		return 0;
	}
	if (vhost[0] == ':')
	{
		sendto_one(sptr, ":%s 514 %s :*** SETHOST Error:A hostname cannot start with ':'",
			me.name, sptr->name);
		return 0;
	}

	if (MyClient(sptr) && !strcmp(GetHost(sptr), vhost))
	{
		sendto_one(sptr,
		    ":%s 514 %s :*** SETHOST Error: requested host is same as current host.",
		    me.name, parv[0]);
		return 0;
	}


		/* hide it */
		sptr->umodes |= UMODE_HIDE;
		//sptr->umodes |= UMODE_SETHOST;
		/* get it in */
	/*	if (sptr->user->mask)
		{
			MyFree(sptr->user->mask);
			//sptr->user->mask = 0;
		}  CAUSES CRASBUG on fucky systems */
		strncpy(sptr->user->mask, vhost, HOSTLEN + 1);
		//sptr->user->mask = strdup(vhost);
		/* spread it out */
		sendto_serv_butone(cptr, ":%s SETHOST %s %s", parv[0], parv[1], parv[2]);

	if (MyConnect(sptr))
	{
		sendto_one(sptr, ":%s MODE %s :+x", sptr->name, sptr->name);
		sendto_one(sptr,
		    ":%s 514 %s :Your mask is now (%s!%s@%s) - To disable it type /mode %s -x",
		    me.name, parv[0], parv[0], sptr->user->username, vhost,
		    parv[0]);
	}
	return 0;
}


/*
 * m_chghost() added by Kei
 * 2007-Mar-21
 * parv[0] - sender
 * parv[1] - nick to change
 * parv[2] - new host
*/
int m_chghost(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
	aClient *acptr;

	if (MyClient(sptr) && !IsSRoot(sptr))
	{
		sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name,
			parv[0]);
		return 0;
	}

	if ((parc < 3) || !*parv[2])
	{
		sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, sptr->name, "CHGHOST");
		return 0;
	}

	if (strlen(parv[2]) > (HOSTLEN))
	{
		sendto_one(sptr, ":%s 514 %s :*** CHGHOST Error: Requested hostname too long -- rejected.",
			me.name, sptr->name);
		return 0;
	}

	if (!valid_host(parv[2]))
	{
		sendto_one(sptr, ":%s 514 %s :*** CHGHOST Error: A hostname may only contain a-z, A-Z, 0-9, '-', '.'",
			me.name, sptr->name);
		return 0;
	}

	if (parv[2][0] == ':')
	{
		sendto_one(sptr, ":%s 514 %s :*** A hostname cannot start with ':'",
			me.name, sptr->name);
		return 0;
	}

	if ((acptr = find_person(parv[1], NULL)))
	{
		if (!strcmp(GetHost(acptr), parv[2]))
		{
			sendto_one(sptr, ":%s 514 %s :*** CHGHOST Error: requested host is same as current host.",
				me.name, sptr->name);
			return 0;
		}

		if (!IsULine(sptr, sptr))
		{
			sendto_umode(UMODE_OPER,
			    "%s changed the vhost of %s (%s@%s) to be %s",
			    sptr->name, acptr->name, acptr->user->username,
			    acptr->user->host, parv[2]);
		}

		acptr->umodes |= UMODE_HIDE;
		//acptr->umodes |= UMODE_SETHOST;
		sendto_serv_butone(cptr, ":%s CHGHOST %s %s", parv[0], parv[1], parv[2]);

		if (acptr->user->mask)
		{
			acptr->user->mask[0] = '\0';
			//acptr->user->mask = 0;
		}
		//acptr->user->mask = strdup(parv[2]);
		strncpy(acptr->user->mask, parv[2], HOSTLEN + 1);
		return 0;
	}
	else
	{
		sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, sptr->name,
		    parv[1]);
		return 0;
	}
	return 0;
}
